BoW model

BoW(Bag-of-Word)
텍스트나 단어 같은 범주형 데이터를 머신 러닝 알고리즘에 주입하기 전에 수치 형태로 변환해야 한다.
BoW는 텍스트를 수치 특성 벡터로 표현하는 방법이다.

1. 전체 문서에 대해 고유한 토큰(token), 예를 들어 단어로 이루어진 어휘 사전(vocabulary)을 만든다.
2. 특정 문서에 각 단어가 얼마나 자주 등장하는지 헤아려 문서의 특성 벡터를 만든다.

각 문서에 있는 고유한 단어는 BoW 어휘사전에 있는 모든 단어의 일부분에 지나지 않으므로,
특성 벡터는 대부분이 0으로 채워진다. 위와 같은 특성 벡터를 희소(sparse)하다고 한다.
scikit-learn CountVectorizer
CountVectorizer 클래스를 사용해서 각가의 문서에 있는 단어 카운트를 기반으로 BoW 모델을 만들 수 있다.
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
count=CountVectorizer()
docs=np.array(['The sun is shining', 'The weather is sweet', 'The sun is shining, the weather is sweet, and one and one is two'])
bag=count.fit_transform(docs)
print(count.vocabulary_)

{'the': 6, 'sun': 4, 'is': 1, 'shining': 3, 'weather': 8, 'sweet': 5, 'and': 0, 'one': 2, 'two': 7}

print(bag.toarray())

[[0 1 0 1 1 0 1 0 0]

 [0 1 0 0 0 1 1 0 1]

 [2 3 2 1 1 1 2 1 1]]

각각의 단어에 대해서 인덱싱이 매겨지고, fit_trainsform(docs) 를 통해서 docs의 단어들 갯수를 벡터로 출력
인덱스 1(is)는 세문장에 모두 포함되어 있다.(1, 1, 3) 위와 같은 포함된 숫자를 단어 빈도(term frequency)라고 한다.

문서 d에 등장한 단어 t의 횟수를 tf(t, d)와 같이 표기한다.

(BoW 모델에서 단어의 인덱스 순서는 알파벳 순서를 따른다.)
n-gram
1-그램(1-gram) 혹은 유니그램(unigram) 모델은 어휘사전에 있는 각 아이템 또는 토큰이 하나의 단어를 표현한다.
일반화하면 NLP에서 연속된 아이템(단어, 문자, 기호)의 시퀀스를 n-그램(n-gram)이라고 한다.

카나리스 등은 3 또는 4의 n-그램이 이메일 스팸 필터링에서 좋은 성능을 낸다고 밝혔다.

ex) “ the sun is shining”
1-gram: “the” “sun” “is” “shining”
2-gram: “the sun” “sun is” “is shinging”

사이킷런에서 CountVectorizer 클래스에서 ngram_range 매개변수를 통해서 다양한 n-gram 모델을 만들 수 있다.
default 값은 1-그램 이다.(ngram_range=(2, 2) 처럼 지정해서 2-그램 표현으로 변경)
tf-idf
텍스트 데이터를 분석할 때, 클래스 레이블이 다른 문서에 같은 단어들이 나타나는 경우를 종종 볼 수 있다.
일반적으로 자주 등장하는 단어는 유용하거나 판별에 필요한 정보를 가지고 있지 않다.

tf-idf(term frequency-inverse document frequency) 기법은 자주 등장하는 단어의 가중치를 낮추는 기법이다.
tf-idf는 단어 빈도와 역문서 빈도(inverse document frequency)의 곱으로 정의된다.

tf-idf(t, d)=tfIt, d) X idf(t, d)
idf(t, d)=log( n_d/{1+df( d, t)} )
idf는 역문서 빈도이다. n_d는 전체 문서 개수
df(d, t)는 단어 t가 포함된 문서 d의 개수
from sklearn.feature_extraction.text import TfidfTransformer
tfidf=TfidfTransformer(use_idf=True, norm='l2', smooth_idf=True)
np.set_printoptions(precision=2)
print(tfidf.fit_transform(count.fit_transform(docs)).toarray())

[[0.   0.43 0.   0.56 0.56 0.   0.43 0.   0.  ]

 [0.   0.43 0.   0.   0.   0.56 0.43 0.   0.56]

 [0.5  0.45 0.5  0.19 0.19 0.19 0.3  0.25 0.19]]

이 때 가장 많이 나타났던 is가 비교적 작은 tf-idf를 가짐을 알 수 있다.
is는 첫 번째와 두 번째 문서에서도 나타나므로 판별에 유용한 정보를 가지고 있지 않다.

사이킷런에서는 위의 공식과 약간 다르게 idf, tf-idf를 계산한다.
머신러닝교과서with파이썬,사이킷런,텐서플로_개정3판pg.330
TfidTransformer 클래스는 tf-idf를 직접 정규화한다.(기본적으로 L2 정규화를 적용)
정규화되지 않은 특성 벡터 v를 L2-노름으로 나누면 길이가 1인 벡터가 반환됨

tf가 클수록, df가 작을수록 tf-dif는 값이 크다.